package com.fuint.freemarker;

import freemarker.template.Configuration;
import freemarker.template.TemplateException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.boot.autoconfigure.freemarker.FreeMarkerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerView;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * freemarker 配置
 */
@org.springframework.context.annotation.Configuration
public class FreemarkerConfig {

	private static final Logger logger = LoggerFactory.getLogger(FreemarkerConfig.class);

	@Autowired
	private FreeMarkerProperties properties;

	@Bean
	public FreeMarkerViewResolver freeMarkerViewResolver() {
		FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
		resolver.setViewClass(FreeMarkerView.class);
		resolver.setCache(properties.isCache());
		resolver.setContentType(properties.getContentType().toString());
		resolver.setRequestContextAttribute(properties.getRequestContextAttribute());
		resolver.setExposeSpringMacroHelpers(properties.isExposeSpringMacroHelpers());
		resolver.setExposeRequestAttributes(properties.isExposeRequestAttributes());
		resolver.setExposeSessionAttributes(properties.isAllowSessionOverride());
		resolver.setAllowRequestOverride(properties.isAllowRequestOverride());
		resolver.setAllowSessionOverride(properties.isAllowSessionOverride());
		resolver.setSuffix(properties.getSuffix());
		resolver.setPrefix("/");
		resolver.setOrder(0);
		resolver.setAttributesMap(getFreemarkerStaticModels());
		return resolver;
	}

	@Bean
	public FreeMarkerConfigurer freeMarkerConfigurer(@Value("${freemarker.auto_import}") String autoImport,
			@Value("${freemarker.auto_include}") String autoInclude) throws Exception {
		FreeMarkerConfigurer config = new FreeMarkerConfigurer();
		writerProperties(config);
		Configuration configuration = null;
		try {
			configuration = config.createConfiguration();
		} catch (IOException e) {
			logger.error("FreemarkerConfig", e);
			throw new RuntimeException("freemarker配置bean，IO异常", e);
		} catch (TemplateException e) {
			logger.error("FreemarkerConfig", e);
			throw new RuntimeException("freemarker配置bean异常", e);
		}
		setAutoImport(autoImport, configuration);
		setAutoInclude(autoInclude, configuration);
		config.setConfiguration(configuration);
		return config;
	}

	private void writerProperties(FreeMarkerConfigurer config) {
		config.setTemplateLoaderPaths(this.properties.getTemplateLoaderPath());
		config.setPreferFileSystemAccess(this.properties.isPreferFileSystemAccess());
		config.setDefaultEncoding(this.properties.getCharsetName());
		Properties settings = new Properties();
		settings.putAll(this.properties.getSettings());
		config.setFreemarkerSettings(settings);
	}

	private void setAutoImport(String autoImport, Configuration configuration) throws Exception {
		if ("_".equals(autoImport.trim())) {
			return;
		}
		String[] imports = autoImport.split(";");
		Map<String, String> importMap = new HashMap<String, String>(imports.length);
		for (String s : imports) {
			String[] keyValue = s.split("as");
			if (keyValue.length != 2) {
				logger.error("freemarker配置auto_import格式不正确 ");
				throw new RuntimeException("freemarker配置auto_import格式不正确");
			}
			logger.info(s);
			importMap.put(keyValue[1].trim(), keyValue[0].trim());
		}
		configuration.setAutoImports(importMap);
	}

	private void setAutoInclude(final String autoInclude, Configuration configuration) {
		if ("_".equals(autoInclude.trim())) {
			return;
		}
		String[] includes = autoInclude.split(";");
		for (String s : includes) {
			System.out.println(s);
		}
		List<String> list = new ArrayList<String>(Arrays.asList(includes));
		configuration.setAutoIncludes(list);
	}

	@Bean
	public PropertiesFactoryBean getFreemarkerPropertiesFactoryBean() {
		PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
		propertiesFactoryBean.setLocation(new ClassPathResource("staticClass.properties"));
		return propertiesFactoryBean;
	}

	@Bean
	public FreemarkerStaticModels getFreemarkerStaticModels() {
		FreemarkerStaticModels freemarkerStaticModels = FreemarkerStaticModels.getInstance();
		PropertiesFactoryBean propertiesFactoryBean = getFreemarkerPropertiesFactoryBean();
		try {
			Properties properties = propertiesFactoryBean.getObject();
			freemarkerStaticModels.setStaticModels(properties);
		} catch (IOException e) {
			logger.error("freemarker static class load error : {}", e);
			throw new RuntimeException("freemarker static class load error");
		}
		return freemarkerStaticModels;
	}
}
